{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 0.导入库"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0.1 常用的库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import numpy as np\n",
    "import time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0.2 需要使用的库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import pickle\n",
    "import re"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0.3 基本方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\ProgramData\\Anaconda3\\lib\\site-packages\\h5py\\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "# 实时更新进度条\n",
    "def print_flush(print_string):\n",
    "    print(print_string, end='\\r')\n",
    "    sys.stdout.flush()\n",
    "\n",
    "# 导入深度学习库tensorflow    \n",
    "import tensorflow as tf    \n",
    "#  获取显存动态增长的会话 \n",
    "def get_session():\n",
    "    config = tf.ConfigProto()\n",
    "    config.gpu_options.allow_growth = True\n",
    "    session = tf.Session(config=config)\n",
    "    return session"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 文件内容的列表"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.1 文本文件路径的列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "文本文件路径的列表长度: 836075\n"
     ]
    }
   ],
   "source": [
    "def get_txtFilePath_list(root_dirPath):\n",
    "    txtFilePath_list = []\n",
    "    sub_dirName_list = next(os.walk(root_dirPath))[1]\n",
    "    for sub_dirName in sub_dirName_list:\n",
    "        sub_dirPath = os.path.join(root_dirPath, sub_dirName)\n",
    "        fileName_list = next(os.walk(sub_dirPath))[2]\n",
    "        filePath_list = [os.path.join(sub_dirPath, k) for k in fileName_list]\n",
    "        txtFilePath_list.extend(filePath_list)\n",
    "    return txtFilePath_list\n",
    "\n",
    "\n",
    "root_dirPath = '../resources/THUCNews/'\n",
    "txtFilePath_list = get_txtFilePath_list(root_dirPath)\n",
    "print('文本文件路径的列表长度:', len(txtFilePath_list))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 读取所有文本文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "836075/ 836075 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 进度百分比:100.00% 读取速度:2088.18文件/秒 总共花费时间:400.38秒\r"
     ]
    }
   ],
   "source": [
    "def get_fileContent(txtFilePath):\n",
    "    with open(txtFilePath, 'r', encoding='utf8') as file:\n",
    "        fileContent = file.read()\n",
    "    return fileContent\n",
    "\n",
    "\n",
    "sequence_length = 600\n",
    "sample_quantity = len(txtFilePath_list)\n",
    "startTime = time.time()\n",
    "content_list = []\n",
    "for i in range(sample_quantity):\n",
    "    txtFilePath = txtFilePath_list[i]\n",
    "    fileContent = get_fileContent(txtFilePath)\n",
    "    fileContent_1 = re.sub('\\s+', ' ', fileContent)\n",
    "    fileContent_2 = fileContent_1[:sequence_length]\n",
    "    content_list.append(fileContent_2)\n",
    "    # 打印提示信息，动态刷新进度条\n",
    "    index = i + 1\n",
    "    if index % 100 == 0 or index==sample_quantity:\n",
    "        percent = index / sample_quantity * 100\n",
    "        percent_int = int(percent)\n",
    "        half_percent_int = int(percent_int / 2)\n",
    "        string_0 = '%d/ %d ' %(index, sample_quantity)\n",
    "        string_1 = '>' * half_percent_int + ' ' * (50-half_percent_int)\n",
    "        string_2 = ' 进度百分比:%.2f%%' %percent\n",
    "        usedTime = time.time() - startTime\n",
    "        string_3 = ' 读取速度:%.2f文件/秒' %(index/usedTime)\n",
    "        string_4 = ' 总共花费时间:%.2f秒' %(usedTime)\n",
    "        print_string = string_0 + string_1 + string_2 + string_3 + string_4\n",
    "        print_flush(print_string)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3 把文件内容列表保存为pickle文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "pickleFilePath = '../resources/content_list.pickle'\n",
    "with open(pickleFilePath, 'wb') as file:\n",
    "    pickle.dump(content_list, file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.4 从pickle文件加载文件内容列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "pickleFilePath = '../resources/content_list.pickle'\n",
    "with open(pickleFilePath, 'rb') as file:\n",
    "    content_list = pickle.load(file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 样本标签的列表"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1 获取样本标签的列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "样本标签的列表长度: 836075\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "科技    162929\n",
       "股票    154398\n",
       "体育    131604\n",
       "娱乐     92632\n",
       "时政     63086\n",
       "社会     50849\n",
       "教育     41936\n",
       "财经     37098\n",
       "家居     32586\n",
       "游戏     24373\n",
       "房产     20050\n",
       "时尚     13368\n",
       "彩票      7588\n",
       "星座      3578\n",
       "dtype: int64"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def get_label_list(root_dirPath):\n",
    "    label_list = []\n",
    "    sub_dirName_list = next(os.walk(root_dirPath))[1]\n",
    "    for sub_dirName in sub_dirName_list:\n",
    "        sub_dirPath = os.path.join(root_dirPath, sub_dirName)\n",
    "        fileName_list = next(os.walk(sub_dirPath))[2]\n",
    "        part_label_list = [sub_dirName] * len(fileName_list)\n",
    "        label_list.extend(part_label_list)\n",
    "    return label_list\n",
    "\n",
    "\n",
    "root_dirPath = '../resources/THUCNews/'\n",
    "label_list = get_label_list(root_dirPath)\n",
    "print('样本标签的列表长度:', len(label_list)) \n",
    "pd.value_counts(label_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 字列表"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1 根据文件内容列表，统计计数获得出现次数排名前6999的字\n",
    "#### 排名7000以后的字统一用'PAD'表示"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "836075/ 836075 进度百分比: 100.00% 花费时间: 81.30秒\r"
     ]
    }
   ],
   "source": [
    "from collections import Counter\n",
    "\n",
    "def get_word_list(content_list, size):\n",
    "    startTime = time.time()\n",
    "    counter = Counter()\n",
    "    sample_quantity = len(content_list)\n",
    "    for i, content in enumerate(content_list, 1):\n",
    "        counter.update(content)\n",
    "        if i%1000==0 or i==sample_quantity:\n",
    "            string_0 = '%d/ %d' %(i, sample_quantity)\n",
    "            string_1 = ' 进度百分比: %.2f%%' %(i/sample_quantity*100)\n",
    "            usedTime = time.time() - startTime\n",
    "            string_2 = ' 花费时间: %.2f秒' %usedTime\n",
    "            print_string = string_0 + string_1 + string_2\n",
    "            print_flush(print_string)\n",
    "    word_list_1 = [k[0] for k in counter.most_common(size-1)]\n",
    "    word_list = ['PAD'] + word_list_1\n",
    "    return word_list\n",
    "\n",
    "\n",
    "vocabulary_size = 7000\n",
    "word_list = get_word_list(content_list, vocabulary_size)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 把字列表保存为pickle文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "pickleFilePath = '../resources/word_list.pickle'\n",
    "with open(pickleFilePath, 'wb') as file:\n",
    "    pickle.dump(word_list, file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3 从pickle文件加载字列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "pickleFilePath = '../resources/word_list.pickle'\n",
    "with open(pickleFilePath, 'rb') as file:\n",
    "    word_list = pickle.load(file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.数据准备"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1 get_X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "import keras\n",
    "\n",
    "# sequence_length中文叫做序列长度，根据自己经验设置\n",
    "# sequence_length设置为600，即根据文章的前600字则可判断文章类型\n",
    "sequence_length = 600\n",
    "word2id_dict = dict([(b, a) for a, b in enumerate(word_list)])\n",
    "    \n",
    "    \n",
    "# 获取一篇文章对应的字id列表    \n",
    "def get_id_list(index):\n",
    "    content = index if isinstance(index, str) else content_list[index]\n",
    "    id_list = []\n",
    "    for word in content[:sequence_length]:\n",
    "        if word in word2id_dict:\n",
    "            id_ = word2id_dict[word]\n",
    "            id_list.append(id_)\n",
    "        else:\n",
    "            id_list.append(0)\n",
    "    return id_list       \n",
    "\n",
    "\n",
    "# 获取多篇文章的字id列表\n",
    "def get_X(indexes):\n",
    "    idList_list = [get_id_list(k) for k in indexes]\n",
    "    X = keras.preprocessing.sequence.pad_sequences(idList_list, sequence_length)        \n",
    "    return X"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2 get_Y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "labelEncoder = LabelEncoder()\n",
    "labelEncoder.fit(label_list)\n",
    "category_quantity = labelEncoder.classes_.shape[0]\n",
    "\n",
    "\n",
    "# 获取多篇文章标签one-hot编码矩阵\n",
    "def get_Y(indexes):\n",
    "    part_label_list = [label_list[k] for k in indexes]\n",
    "    oneHot_2d_array = labelEncoder.transform(part_label_list)\n",
    "    Y = keras.utils.to_categorical(oneHot_2d_array, category_quantity)\n",
    "    return Y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.3 使用带权重的抽样策略，计算每个样本的权重"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_probability_list(label_list):\n",
    "    count_series = pd.value_counts(label_list)\n",
    "    category_quantity = len(count_series)\n",
    "    category_weights = 1 / category_quantity\n",
    "    label2weights_dict = dict([(a, b) for a, b in zip(count_series.index, category_weights/count_series)])\n",
    "    probability_list = [label2weights_dict[k] for k in label_list]\n",
    "    return probability_list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.4 批量数据生产者线程"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "import threading\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "sample_quantity = len(label_list)\n",
    "index_1d_array = np.arange(sample_quantity)\n",
    "train_index_1d_array, test_index_1d_array = train_test_split(index_1d_array, random_state=2019)\n",
    "train_label_list = [label_list[k] for k in train_index_1d_array]\n",
    "train_probability_list = get_probability_list(train_label_list)\n",
    "batch_size = 128\n",
    "\n",
    "\n",
    "class BatchDataThread(threading.Thread):\n",
    "    def __init__(self, queue):\n",
    "        super(BatchDataThread, self).__init__()\n",
    "        self.queue = queue\n",
    "        self.start()\n",
    "    \n",
    "    def run(self):\n",
    "        while not self._is_stopped:\n",
    "            if self.queue.qsize() < 4:\n",
    "                selected_indexes = np.random.choice(\n",
    "                    train_index_1d_array, size=batch_size, p=train_probability_list)\n",
    "                batch_X = get_X(selected_indexes)\n",
    "                batch_Y = get_Y(selected_indexes)\n",
    "                put_tuple = batch_X.astype('int32'), batch_Y.astype('float32')\n",
    "                self.queue.put(put_tuple)\n",
    "            time.sleep(0.0001)            "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.5 批量数据生成器类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "import queue\n",
    "\n",
    "class BatchDataGenerator(object):\n",
    "    def __init__(self, worker_quantity=4):\n",
    "        self.queue = queue.Queue()\n",
    "        for i in range(worker_quantity):\n",
    "            BatchDataThread(self.queue)\n",
    "            \n",
    "    def __iter__(self):\n",
    "        return self\n",
    "    \n",
    "    def __next__(self):\n",
    "        batch_data = self.queue.get()\n",
    "        return batch_data\n",
    "    \n",
    "    \n",
    "batchData_generator = BatchDataGenerator()    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.搭建神经网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Logging before flag parsing goes to stderr.\n",
      "W0828 09:59:24.074238  1516 deprecation.py:506] From C:\\ProgramData\\Anaconda3\\lib\\site-packages\\tensorflow\\python\\ops\\init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Call initializer instance with the dtype argument instead of passing it to the constructor\n",
      "W0828 09:59:24.089231  1516 deprecation.py:323] From <ipython-input-12-a0548f6617c7>:11: conv1d (from tensorflow.python.layers.convolutional) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use `tf.keras.layers.Conv1D` instead.\n",
      "W0828 09:59:24.303164  1516 deprecation.py:323] From <ipython-input-12-a0548f6617c7>:22: dense (from tensorflow.python.layers.core) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use keras.layers.dense instead.\n"
     ]
    }
   ],
   "source": [
    "tf.reset_default_graph()\n",
    "X_holder = tf.placeholder(tf.int32, [None, sequence_length])\n",
    "Y_holder = tf.placeholder(tf.float32, [None, category_quantity])\n",
    "data_0 = X_holder # N *  600\n",
    "vocabulary_size = 7000\n",
    "embedding_size = 100\n",
    "layer_1 = tf.get_variable('embedding', [vocabulary_size, embedding_size])\n",
    "data_1 = tf.nn.embedding_lookup(layer_1, data_0) # N * 600 * 100\n",
    "filter_quantiy = 128 \n",
    "layer_2 = tf.layers.conv1d # 3 * 100 * 128\n",
    "data_2 = layer_2(data_1, filter_quantiy, 3, padding='SAME') # N * 600 * 128\n",
    "layer_3 = tf.layers.conv1d # 5 * 100 * 128\n",
    "data_3 = layer_3(data_1, filter_quantiy, 5, padding='SAME') # N * 600 * 128\n",
    "layer_4 = tf.layers.conv1d # 7 * 100 * 128\n",
    "data_4 = layer_4(data_1, filter_quantiy, 7, padding='SAME') # N * 600 * 128\n",
    "layer_5 = tf.concat\n",
    "data_5 = layer_5([data_2, data_3, data_4], axis=2) # N * 600 * 384\n",
    "layer_6 = tf.reduce_max\n",
    "data_6 = layer_6(data_5, [1]) # N * 384\n",
    "layer_7 = tf.layers.dense # 384 * 128\n",
    "fc1_units = 128\n",
    "data_7 = layer_7(data_6, fc1_units) # N * 128\n",
    "layer_8 = tf.nn.relu\n",
    "data_8 = layer_8(data_7) # N * 128\n",
    "layer_9 = tf.layers.dense\n",
    "data_9 = layer_9(data_8, category_quantity) # N * 14\n",
    "layer_10 = tf.nn.softmax\n",
    "data_10 = layer_10(data_9) # N * 14\n",
    "layer_11 = tf.nn.softmax_cross_entropy_with_logits_v2\n",
    "data_11 = layer_11(labels=Y_holder, logits=data_9) # N\n",
    "loss = tf.reduce_mean(data_11) # 1\n",
    "learning_rate = 5e-4\n",
    "optimizer = tf.train.AdamOptimizer(learning_rate)\n",
    "train = optimizer.minimize(loss)\n",
    "isCorrect = tf.equal(tf.argmax(Y_holder, 1), tf.argmax(data_10, 1))\n",
    "accuracy = tf.reduce_mean(tf.cast(isCorrect, tf.float32))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6.参数初始化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "init = tf.global_variables_initializer()\n",
    "session = get_session()\n",
    "session.run(init)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7.模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "步数:10000 损失值:0.0470 准确率:0.9844 训练速度:11.10步/秒\r"
     ]
    }
   ],
   "source": [
    "train_steps = 10000\n",
    "startTime = time.time()\n",
    "for step in range(1, train_steps+1):\n",
    "    batch_X, batch_Y = next(batchData_generator)\n",
    "    session.run(train, {X_holder:batch_X, Y_holder:batch_Y})\n",
    "    if step % 2 == 0 :\n",
    "        loss_value, accuracy_value = session.run([loss, accuracy], {X_holder:batch_X, Y_holder:batch_Y})\n",
    "        usedTime = time.time() - startTime\n",
    "        speed = step / usedTime\n",
    "        print_string = '步数:%d 损失值:%.4f 准确率:%.4f 训练速度:%.2f步/秒' %(\n",
    "            step, loss_value, accuracy_value, speed)\n",
    "        print_flush(print_string)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8.模型测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "选出文本内容为:  高房价痛的不仅是普通人 明星买房也三思(图) 那些成名后依旧“蜗居”的明星…… 电视剧《蜗居》的热播，让人们深刻体会了高房价之下的残酷人生，高房价甚至毁掉了年青一代的幸福。日前，有网友发博文曝光了现在还在租房子住的十大当红明星，引发热议，紧接着，更多的明星公开表示自己“买不起房”，一部明星版《蜗居》俨然在上演。这些明星，果真买不起房吗？还是，挣钱再多也难以赶上飙涨的房价？还是，他们要的不是房子而是性价比？策划：周娴 撰文：记者 张素芹 房价凭什么疯涨？ 《蜗居》主创海清文章，买的都是二手房 海清、文章买了二手房，邬君梅和张嘉译坦言每月还房贷……《蜗居》中的明星们众口一词：“房价这么高，凭什么？” 饰演郭海萍的海清曾“抱怨”：现实生活中自己也是房奴。迟疑了很久，直到北京房价大涨，才终于出手花了多年积蓄在三环外买了一处二手房。“买房子缺钱，把我逼得去买彩票，我在剧组一个月时间里，每周都去买次彩票，每次买十块钱。” 饰演小贝的文章，也和海清一样，倾尽自己和家人的全力，买了套二手房：“我买房不是为了投资，是真的要去住。自从我开枝散叶，家里有老人有小孩后，一家人就真的没地住了。”文章如是说。 点评：纷繁复杂的原因，使涨价成为2009年楼市的关键词。京城，更是居不易。从今年春节之后的“小阳春”，到“红五月”、“金七银八”，再到一手房9月成交的小幅收窄、10月的小幅回升，涨价，成了贯穿今年京城楼\n",
      "真实标签:  娱乐\n",
      "预测标签:  娱乐 \n",
      "\n",
      "对于任意文本做分类预测，例如:\n",
      "predict(\"足球篮球\") : 体育\n"
     ]
    }
   ],
   "source": [
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "def predict(input_content):\n",
    "    id_list = get_id_list(input_content)\n",
    "    X = keras.preprocessing.sequence.pad_sequences([id_list], sequence_length)    \n",
    "    Y = session.run(data_10, {X_holder:X}) # 1 * 10\n",
    "    y = np.argmax(Y, axis=1) # 1\n",
    "    label = labelEncoder.inverse_transform(y)[0]\n",
    "    return label\n",
    "\n",
    "selected_index = np.random.choice(test_index_1d_array, 1)[0]\n",
    "selected_content = content_list[selected_index]\n",
    "true_label = label_list[selected_index]\n",
    "predict_label = predict(selected_content)\n",
    "print('选出文本内容为: ', selected_content)\n",
    "print('真实标签: ', true_label)\n",
    "print('预测标签: ', predict_label, '\\n')\n",
    "print('对于任意文本做分类预测，例如:')\n",
    "input_content = \"足球篮球\"\n",
    "print('predict(\"%s\") :' %input_content, predict(input_content))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 9.混淆矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "209019/ 209019 花费时间:71.07秒\r"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>体育</th>\n",
       "      <th>娱乐</th>\n",
       "      <th>家居</th>\n",
       "      <th>彩票</th>\n",
       "      <th>房产</th>\n",
       "      <th>教育</th>\n",
       "      <th>时尚</th>\n",
       "      <th>时政</th>\n",
       "      <th>星座</th>\n",
       "      <th>游戏</th>\n",
       "      <th>社会</th>\n",
       "      <th>科技</th>\n",
       "      <th>股票</th>\n",
       "      <th>财经</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>体育</th>\n",
       "      <td>32559</td>\n",
       "      <td>109</td>\n",
       "      <td>12</td>\n",
       "      <td>44</td>\n",
       "      <td>4</td>\n",
       "      <td>14</td>\n",
       "      <td>5</td>\n",
       "      <td>38</td>\n",
       "      <td>0</td>\n",
       "      <td>35</td>\n",
       "      <td>76</td>\n",
       "      <td>81</td>\n",
       "      <td>4</td>\n",
       "      <td>7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>娱乐</th>\n",
       "      <td>112</td>\n",
       "      <td>22133</td>\n",
       "      <td>58</td>\n",
       "      <td>1</td>\n",
       "      <td>32</td>\n",
       "      <td>26</td>\n",
       "      <td>44</td>\n",
       "      <td>57</td>\n",
       "      <td>5</td>\n",
       "      <td>52</td>\n",
       "      <td>256</td>\n",
       "      <td>311</td>\n",
       "      <td>6</td>\n",
       "      <td>19</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>家居</th>\n",
       "      <td>15</td>\n",
       "      <td>70</td>\n",
       "      <td>7896</td>\n",
       "      <td>0</td>\n",
       "      <td>57</td>\n",
       "      <td>11</td>\n",
       "      <td>23</td>\n",
       "      <td>12</td>\n",
       "      <td>4</td>\n",
       "      <td>9</td>\n",
       "      <td>38</td>\n",
       "      <td>159</td>\n",
       "      <td>14</td>\n",
       "      <td>17</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>彩票</th>\n",
       "      <td>35</td>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>1835</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>4</td>\n",
       "      <td>0</td>\n",
       "      <td>4</td>\n",
       "      <td>44</td>\n",
       "      <td>7</td>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>房产</th>\n",
       "      <td>0</td>\n",
       "      <td>8</td>\n",
       "      <td>39</td>\n",
       "      <td>0</td>\n",
       "      <td>4714</td>\n",
       "      <td>5</td>\n",
       "      <td>1</td>\n",
       "      <td>26</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>41</td>\n",
       "      <td>53</td>\n",
       "      <td>48</td>\n",
       "      <td>40</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>教育</th>\n",
       "      <td>12</td>\n",
       "      <td>23</td>\n",
       "      <td>24</td>\n",
       "      <td>4</td>\n",
       "      <td>18</td>\n",
       "      <td>9750</td>\n",
       "      <td>6</td>\n",
       "      <td>81</td>\n",
       "      <td>4</td>\n",
       "      <td>16</td>\n",
       "      <td>317</td>\n",
       "      <td>198</td>\n",
       "      <td>6</td>\n",
       "      <td>15</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>时尚</th>\n",
       "      <td>7</td>\n",
       "      <td>36</td>\n",
       "      <td>47</td>\n",
       "      <td>0</td>\n",
       "      <td>7</td>\n",
       "      <td>3</td>\n",
       "      <td>3125</td>\n",
       "      <td>6</td>\n",
       "      <td>0</td>\n",
       "      <td>9</td>\n",
       "      <td>10</td>\n",
       "      <td>33</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>时政</th>\n",
       "      <td>56</td>\n",
       "      <td>67</td>\n",
       "      <td>7</td>\n",
       "      <td>4</td>\n",
       "      <td>56</td>\n",
       "      <td>93</td>\n",
       "      <td>13</td>\n",
       "      <td>14313</td>\n",
       "      <td>0</td>\n",
       "      <td>17</td>\n",
       "      <td>476</td>\n",
       "      <td>501</td>\n",
       "      <td>77</td>\n",
       "      <td>67</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>星座</th>\n",
       "      <td>2</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>899</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>游戏</th>\n",
       "      <td>4</td>\n",
       "      <td>4</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>5815</td>\n",
       "      <td>12</td>\n",
       "      <td>203</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>社会</th>\n",
       "      <td>24</td>\n",
       "      <td>84</td>\n",
       "      <td>25</td>\n",
       "      <td>26</td>\n",
       "      <td>72</td>\n",
       "      <td>129</td>\n",
       "      <td>6</td>\n",
       "      <td>149</td>\n",
       "      <td>0</td>\n",
       "      <td>19</td>\n",
       "      <td>11725</td>\n",
       "      <td>398</td>\n",
       "      <td>2</td>\n",
       "      <td>48</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>科技</th>\n",
       "      <td>28</td>\n",
       "      <td>114</td>\n",
       "      <td>101</td>\n",
       "      <td>4</td>\n",
       "      <td>27</td>\n",
       "      <td>52</td>\n",
       "      <td>8</td>\n",
       "      <td>211</td>\n",
       "      <td>1</td>\n",
       "      <td>490</td>\n",
       "      <td>474</td>\n",
       "      <td>38648</td>\n",
       "      <td>155</td>\n",
       "      <td>66</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>股票</th>\n",
       "      <td>8</td>\n",
       "      <td>11</td>\n",
       "      <td>56</td>\n",
       "      <td>1</td>\n",
       "      <td>155</td>\n",
       "      <td>16</td>\n",
       "      <td>7</td>\n",
       "      <td>416</td>\n",
       "      <td>0</td>\n",
       "      <td>46</td>\n",
       "      <td>52</td>\n",
       "      <td>1166</td>\n",
       "      <td>35815</td>\n",
       "      <td>1108</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>财经</th>\n",
       "      <td>5</td>\n",
       "      <td>8</td>\n",
       "      <td>25</td>\n",
       "      <td>5</td>\n",
       "      <td>41</td>\n",
       "      <td>11</td>\n",
       "      <td>2</td>\n",
       "      <td>45</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>65</td>\n",
       "      <td>177</td>\n",
       "      <td>361</td>\n",
       "      <td>8525</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       体育     娱乐    家居    彩票    房产    教育    时尚     时政   星座    游戏     社会  \\\n",
       "体育  32559    109    12    44     4    14     5     38    0    35     76   \n",
       "娱乐    112  22133    58     1    32    26    44     57    5    52    256   \n",
       "家居     15     70  7896     0    57    11    23     12    4     9     38   \n",
       "彩票     35      4     1  1835     1     0     0      4    0     4     44   \n",
       "房产      0      8    39     0  4714     5     1     26    0     3     41   \n",
       "教育     12     23    24     4    18  9750     6     81    4    16    317   \n",
       "时尚      7     36    47     0     7     3  3125      6    0     9     10   \n",
       "时政     56     67     7     4    56    93    13  14313    0    17    476   \n",
       "星座      2      0     3     0     0     0     3      0  899     0      1   \n",
       "游戏      4      4     3     0     0     2     2      3    0  5815     12   \n",
       "社会     24     84    25    26    72   129     6    149    0    19  11725   \n",
       "科技     28    114   101     4    27    52     8    211    1   490    474   \n",
       "股票      8     11    56     1   155    16     7    416    0    46     52   \n",
       "财经      5      8    25     5    41    11     2     45    0     1     65   \n",
       "\n",
       "       科技     股票    财经  \n",
       "体育     81      4     7  \n",
       "娱乐    311      6    19  \n",
       "家居    159     14    17  \n",
       "彩票      7      0     2  \n",
       "房产     53     48    40  \n",
       "教育    198      6    15  \n",
       "时尚     33      0     3  \n",
       "时政    501     77    67  \n",
       "星座      0      0     1  \n",
       "游戏    203      1     0  \n",
       "社会    398      2    48  \n",
       "科技  38648    155    66  \n",
       "股票   1166  35815  1108  \n",
       "财经    177    361  8525  "
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "\n",
    "def predict_test():\n",
    "    startTime = time.time()\n",
    "    test_sample_quantity = len(test_index_1d_array)\n",
    "    batch_size  = 100\n",
    "    predict_Y_list = []\n",
    "    for i in range(0, test_sample_quantity, batch_size):\n",
    "        part_index_1d_array = test_index_1d_array[i: i + batch_size]\n",
    "        batch_X = get_X(part_index_1d_array)\n",
    "        predict_Y = session.run(data_10, {X_holder:batch_X})\n",
    "        predict_Y_list.extend(predict_Y)\n",
    "        usedTime = time.time() - startTime\n",
    "        print_string = '%d/ %d 花费时间:%.2f秒' %(i, test_sample_quantity, usedTime)\n",
    "        print_flush(print_string)\n",
    "    print_string = '%d/ %d 花费时间:%.2f秒' %(test_sample_quantity, test_sample_quantity, usedTime)\n",
    "    print_flush(print_string)    \n",
    "    Y = np.array(predict_Y_list)   \n",
    "    y = np.argmax(Y, axis=1)\n",
    "    predict_label_list = labelEncoder.inverse_transform(y)\n",
    "    return predict_label_list\n",
    "\n",
    "\n",
    "test_label_list = [label_list[k] for k in test_index_1d_array]\n",
    "predict_label_list = predict_test()\n",
    "pd.DataFrame(confusion_matrix(test_label_list, predict_label_list), \n",
    "             columns=labelEncoder.classes_,\n",
    "             index=labelEncoder.classes_ )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 10.报告表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Label</th>\n",
       "      <th>Precision</th>\n",
       "      <th>Recall</th>\n",
       "      <th>F1</th>\n",
       "      <th>Support</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>体育</td>\n",
       "      <td>0.990629</td>\n",
       "      <td>0.986995</td>\n",
       "      <td>0.988809</td>\n",
       "      <td>32988</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>娱乐</td>\n",
       "      <td>0.976269</td>\n",
       "      <td>0.957641</td>\n",
       "      <td>0.966865</td>\n",
       "      <td>23112</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>家居</td>\n",
       "      <td>0.951669</td>\n",
       "      <td>0.948468</td>\n",
       "      <td>0.950066</td>\n",
       "      <td>8325</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>彩票</td>\n",
       "      <td>0.953742</td>\n",
       "      <td>0.947341</td>\n",
       "      <td>0.950531</td>\n",
       "      <td>1937</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>房产</td>\n",
       "      <td>0.909336</td>\n",
       "      <td>0.946967</td>\n",
       "      <td>0.927770</td>\n",
       "      <td>4978</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>教育</td>\n",
       "      <td>0.964201</td>\n",
       "      <td>0.930876</td>\n",
       "      <td>0.947246</td>\n",
       "      <td>10474</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>时尚</td>\n",
       "      <td>0.963020</td>\n",
       "      <td>0.951004</td>\n",
       "      <td>0.956974</td>\n",
       "      <td>3286</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>时政</td>\n",
       "      <td>0.931775</td>\n",
       "      <td>0.908935</td>\n",
       "      <td>0.920213</td>\n",
       "      <td>15747</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>星座</td>\n",
       "      <td>0.984666</td>\n",
       "      <td>0.988999</td>\n",
       "      <td>0.986828</td>\n",
       "      <td>909</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>游戏</td>\n",
       "      <td>0.892419</td>\n",
       "      <td>0.961316</td>\n",
       "      <td>0.925587</td>\n",
       "      <td>6049</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>社会</td>\n",
       "      <td>0.862957</td>\n",
       "      <td>0.922720</td>\n",
       "      <td>0.891838</td>\n",
       "      <td>12707</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>科技</td>\n",
       "      <td>0.921617</td>\n",
       "      <td>0.957131</td>\n",
       "      <td>0.939038</td>\n",
       "      <td>40379</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>股票</td>\n",
       "      <td>0.981529</td>\n",
       "      <td>0.921713</td>\n",
       "      <td>0.950681</td>\n",
       "      <td>38857</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>财经</td>\n",
       "      <td>0.859548</td>\n",
       "      <td>0.919534</td>\n",
       "      <td>0.888530</td>\n",
       "      <td>9271</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>999</th>\n",
       "      <td>总体</td>\n",
       "      <td>0.947552</td>\n",
       "      <td>0.946096</td>\n",
       "      <td>0.946396</td>\n",
       "      <td>209019</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    Label  Precision    Recall        F1  Support\n",
       "0      体育   0.990629  0.986995  0.988809    32988\n",
       "1      娱乐   0.976269  0.957641  0.966865    23112\n",
       "2      家居   0.951669  0.948468  0.950066     8325\n",
       "3      彩票   0.953742  0.947341  0.950531     1937\n",
       "4      房产   0.909336  0.946967  0.927770     4978\n",
       "5      教育   0.964201  0.930876  0.947246    10474\n",
       "6      时尚   0.963020  0.951004  0.956974     3286\n",
       "7      时政   0.931775  0.908935  0.920213    15747\n",
       "8      星座   0.984666  0.988999  0.986828      909\n",
       "9      游戏   0.892419  0.961316  0.925587     6049\n",
       "10     社会   0.862957  0.922720  0.891838    12707\n",
       "11     科技   0.921617  0.957131  0.939038    40379\n",
       "12     股票   0.981529  0.921713  0.950681    38857\n",
       "13     财经   0.859548  0.919534  0.888530     9271\n",
       "999    总体   0.947552  0.946096  0.946396   209019"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from sklearn.metrics import precision_recall_fscore_support\n",
    "\n",
    "def eval_model(y_true, y_pred, labels):\n",
    "    # 计算每个分类的Precision, Recall, f1, support\n",
    "    p, r, f1, s = precision_recall_fscore_support(y_true, y_pred)\n",
    "    # 计算总体的平均Precision, Recall, f1, support\n",
    "    tot_p = np.average(p, weights=s)\n",
    "    tot_r = np.average(r, weights=s)\n",
    "    tot_f1 = np.average(f1, weights=s)\n",
    "    tot_s = np.sum(s)\n",
    "    res1 = pd.DataFrame({\n",
    "        u'Label': labels,\n",
    "        u'Precision': p,\n",
    "        u'Recall': r,\n",
    "        u'F1': f1,\n",
    "        u'Support': s\n",
    "    })\n",
    "    res2 = pd.DataFrame({\n",
    "        u'Label': ['总体'],\n",
    "        u'Precision': [tot_p],\n",
    "        u'Recall': [tot_r],\n",
    "        u'F1': [tot_f1],\n",
    "        u'Support': [tot_s]\n",
    "    })\n",
    "    res2.index = [999]\n",
    "    res = pd.concat([res1, res2])\n",
    "    return res[['Label', 'Precision', 'Recall', 'F1', 'Support']]\n",
    "\n",
    "eval_model(test_label_list, predict_label_list, labelEncoder.classes_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 11.模型保存"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'../resources/trained_model/textCnn.ckpt'"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "saver = tf.train.Saver()\n",
    "ckptFilePath = '../resources/trained_model/textCnn.ckpt'\n",
    "saver.save(session, ckptFilePath)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 12.模型加载"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "W0827 23:09:13.827638 17324 deprecation.py:323] From C:\\ProgramData\\Anaconda3\\lib\\site-packages\\tensorflow\\python\\training\\saver.py:1276: checkpoint_exists (from tensorflow.python.training.checkpoint_management) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use standard file APIs to check for files with this prefix.\n"
     ]
    }
   ],
   "source": [
    "saver = tf.train.Saver()\n",
    "session = get_session()\n",
    "ckptFilePath = '../resources/trained_model/textCnn.ckpt'\n",
    "saver.restore(session, ckptFilePath)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
